package benchmark;

import java.io.BufferedInputStream;
import java.io.DataInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import javax.xml.bind.JAXBException;

import serializer.*;
import config.Config;

public class ThroughputBenchmarkReceiver {
	public static void main(String[] args) throws IOException, JAXBException {
		ServerSocket serverSocket = null;
		Socket clientSocket = null;

		ExecutorService executorService = Executors.newFixedThreadPool(1);

		try {
			serverSocket = new ServerSocket(Config.NET_SERVER_PORT,
					Config.NET_BACKLOG,
					InetAddress.getByName(Config.NET_SERVER_IP));
			System.out.println("Benchmark receiver. Waiting for connection...");

			final ISerializer serializer = new JsonSerializer();

			while (clientSocket == null) {
				try {
					clientSocket = serverSocket.accept();
				} catch (IOException e) {
					System.err
							.println("Accept failed. Waiting for connection...");
				}
			}

			System.out.printf(
					"Connection successful. Server IP: %s. Client IP: %s.\n",
					serverSocket.getInetAddress().toString(), clientSocket
							.getInetAddress().toString());
			System.out.println("Waiting for input...");

			try (InputStream socketIn = clientSocket.getInputStream();
					DataInputStream bufferedSocketIn = new DataInputStream(
							new BufferedInputStream(socketIn));
					OutputStream socketOut = clientSocket.getOutputStream();) {

				byte[] buf = new byte[Config.NET_BUF_SIZE];

				int size = Integer.MAX_VALUE;

				for (int i = 0; i < Config.OBJ_COUNT; i++) {
					int totalRcvd = 0;

					int objSize = bufferedSocketIn.readInt();

					while (totalRcvd < objSize) {
						size = bufferedSocketIn.read(buf, totalRcvd, objSize
								- totalRcvd);
						totalRcvd += size;
					}

					final byte[] objectByteBuf = new byte[objSize];
					System.arraycopy(buf, 0, objectByteBuf, 0, objSize);

					executorService.submit(new Runnable() {
						public void run() {
							serializer.decode(objectByteBuf);
						}
					});
				}

				socketOut.write(Config.TX_ACK_BYTE);
				System.out
						.println("All objects has been received. TX ack sent.");
			}
		} finally {
			if (serverSocket != null) {
				serverSocket.close();
			}
			if (clientSocket != null) {
				clientSocket.close();
			}
			executorService.shutdown();
		}
	}
}
